﻿using System;
using Engine;
using Engine.Math;
using EngineDrawer.Effects.ParticleSystem;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ThinkDotNetEngine;
using ThinkDotNetEngine.Bots;
using ThinkDotNetEngine.Bots.Ammos;
using ThinkDotNetEngineDrawer.Bots.Ammos;

namespace ThinkDotNetEngineDrawer.Bots
{
    public class BotDrawer : DrawableGameComponent
    {
        #region  Constructors

        public BotDrawer(Game game, TankBot tankBot)
            : base(game)
        {
            TankBot = tankBot;
            tankBot.Destroyed += TankBotDestroyed;
        }   

        #endregion

        #region Consts

        private const string TurretBoneName = "turret_geo";
        private const string TankModelPath = @"Vehicles\\tank";
        private const double WheelRotationTimeMultiplier = 0.000004f;
        private const string Wheel1BoneName = "l_back_wheel_geo";
        private const string Wheel2BoneName = "r_back_wheel_geo";
        private const string Wheel3BoneName = "l_front_wheel_geo";
        private const string Wheel4BoneName = "r_front_wheel_geo";

        #endregion

        #region Fields

        private ExplosionSystem _explosionSystem;
        readonly private TankBot TankBot;
        private ModelBone _turretBone;
        private ModelBone[] _wheelBones;
        private Matrix[] _boneMatrices;
        private Arena _arena;

        #endregion

        #region Override

        public override void Initialize()
        {
            base.Initialize();
            _arena = (Arena)Game.Services.GetService(typeof(World));
            Game.Components.Add(new MasterAmmoDrawer(Game));
            LoadTank();
            _explosionSystem = new ExplosionSystem(Game);
            Game.Components.Add(_explosionSystem);
        }
        public override void Draw(GameTime gameTime)
        {            
            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;            

            foreach (ModelMesh mesh in TankBot.Model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = TankBot.BoneAbsolutes[mesh.ParentBone.Index] * TankBot.WorldMatrix;
                    effect.View = _arena.ViewMatrix;
                    effect.Projection = _arena.ProjMatrix;
                }
                mesh.Draw();
            }
            base.Draw(gameTime);
        }
        public override void Update(GameTime gameTime)
        {
            if (TankBot.CurrentClip == TankClip.Move)
                UpdateWheels(gameTime.TotalGameTime.Ticks);
            else
                UpdateWheels(0);
            
            UpdateTurrentAndCannon(gameTime);
            TankBot.Update(gameTime);

            TankBot.Model.CopyAbsoluteBoneTransformsTo(TankBot.BoneAbsolutes);

            base.Update(gameTime);
        }

        #endregion

        #region Private Methods
  
      
        private void InitWheelMatrices()
        {
            _wheelBones = new ModelBone[4];
            _wheelBones[0] = TankBot.Model.Bones[Wheel1BoneName];
            _wheelBones[1] = TankBot.Model.Bones[Wheel2BoneName];
            _wheelBones[2] = TankBot.Model.Bones[Wheel3BoneName];
            _wheelBones[3] = TankBot.Model.Bones[Wheel4BoneName];
        }
        private void UpdateWheels(long ticks)
        {
            var wheelsRotationMatrix = Matrix.CreateRotationX((float)(ticks*TankBot.Speed*WheelRotationTimeMultiplier));
            foreach (ModelBone wheel in _wheelBones)
            {
                wheel.Transform = wheelsRotationMatrix*_boneMatrices[wheel.Index];
            }
        }
        private void UpdateTurrentAndCannon(GameTime gameTime)
        {
            _turretBone.Transform = Matrix.CreateRotationY(TankBot.TurretRotation)*_boneMatrices[_turretBone.Index];
            TankBot.CannonBone.Transform = Matrix.CreateRotationX(TankBot.CannonRotation)*
                                           _boneMatrices[TankBot.CannonBone.Index];

        }
        private void LoadTank()
        {
            TankBot.Load(Game,TankModelPath);
            _boneMatrices = new Matrix[TankBot.Model.Bones.Count];
            TankBot.BoneAbsolutes=new Matrix[TankBot.Model.Bones.Count];

            foreach (ModelBone bone in TankBot.Model.Bones)
                _boneMatrices[bone.Index] = bone.Transform;

            _turretBone = TankBot.Model.Bones[TurretBoneName];
            InitWheelMatrices();
        }

        #endregion

        #region Events

        void TankBotDestroyed(object sender, EventArgs e)
        {
            _explosionSystem.Explode(TankBot.Translation,Vector3.Up);
        }

        #endregion

        #region Properties

        public World World { get { return (World) Game.Services.GetService(typeof (World)); } }

        #endregion
    }
}
